<template>
    <div>
        <el-upload action class="file-item upload-item" :show-file-list="false" :accept="accept" :limit="limit"
            :before-upload="beforeUpload" :http-request="emptyFn" :disabled="readonly">
            <div slot="trigger">
                <div v-if="!fileList.length && !readonly" class="item-el pointer box-column box-center lightgray">
                    <i class="el-icon-plus fz_20"></i>
                    <div class="pt_10">
                        {{ isPic ? '上传图片' : '上传文件' }}
                    </div>
                </div>
                <template v-if="isPic">
                    <viewer :images="images">
                        <img class="item-el" v-for="(src, index) in images" :src="src" :key="index" width="40"
                            height="40" />
                    </viewer>
                </template>
                <template v-else>
                    <div class="item-el text box-column box-center" v-for="(item, index) in fileList" :key="index">
                        {{ item.name }}
                    </div>
                </template>
            </div>
        </el-upload>
        <el-input v-show="false" :value.sync="value"></el-input>
    </div>
</template>
<script>
import { find, floor, isEmpty, concat, compact, map, filter } from 'lodash';
import { oosUpload } from '@/utils/oos';
import { linkVerify } from '@/utils';
import 'viewerjs/dist/viewer.css';
import { component as viewer } from 'v-viewer';
export default {
    name: 'UxUpload',
    components: {
        viewer
    },
    model: {
        prop: 'value',
        event: 'updateValue'
    },
    props: {
        // 是否只读(为true时只做展示)
        isPic: {
            type: Boolean,
            default: true
        },
        // 是否只读(为true时只做展示)
        readonly: {
            type: Boolean,
            default: false
        },
        // 表单绑定值(保证用法与普通表单组件一致)
        value: {
            type: String,
            default: ''
        },
        // 最大允许上传文件数量(isSingle为flase时生效)
        // 默认为2是为了避免单文件上传时无法继续选择
        limit: {
            type: Number,
            default: 2
        },
        // 允许上传文件大小(单位b)
        maxSize: {
            type: Number,
            default: 1024 * 1024 * 3
        },
        // 允许上传类型（默认为已配置全部类型）
        // 可用类型由rules配置决定
        acceptType: {
            type: Array,
            default: function () {
                return ['pic'];
            }
        },
        // 是不是单文件上传
        isSingle: {
            type: Boolean,
            default: true
        },
        // 文件名称（阿里云中文件名称基本上都是随机串，这里可以设置一个别名来显示）（只适用于单文件上传）
        fileName: {
            type: String,
            default: ''
        }
    },
    data() {
        return {
            oos: 'fs/bank-upload-file',
            // 上传文件列表
            fileList: [],
            // 文件格式配置
            rules: [
                {
                    name: 'xlsx',
                    // 校验规则
                    rule: [
                        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                        'application/vnd.ms-excel'
                    ],
                    // 文件后缀
                    suffix: ['.xlsx', '.xls']
                },
                {
                    name: 'doc',
                    rule: [
                        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                        'application/msword'
                    ],
                    suffix: ['.doc', '.docx']
                },
                {
                    name: 'pdf',
                    rule: ['application/pdf'],
                    suffix: ['.pdf']
                },
                {
                    name: 'pic',
                    rule: ['image/jpeg', 'image/jpg', 'image/png'],
                    suffix: ['.jpeg', '.jpg', '.png']
                },
                {
                    name: 'ppt',
                    rule: [
                        'application/vnd.ms-powerpoint',
                        'application/vnd.openxmlformats-officedocument.presentationml.presentation'
                    ],
                    suffix: ['.ppt', '.pptx']
                },
                {
                    name: 'txt',
                    rule: ['text/plain'],
                    suffix: ['.txt']
                }
            ],
            // 允许上传类型(根据rules自动生成)
            accept: '',
            // 运行上传类型校验规则(根据rules自动生成)
            acceptRules: [],
            // 允许上传类型提示文案(根据rules自动生成)
            acceptMessage: '',
            // 标识是否正在设置数据，避免重复触发事件
            isUp: false,
            images: []
        };
    },
    watch: {
        // 监听表单绑定值
        // 将字符串数据转换为可识别的数据格式
        value: {
            immediate: true,
            handler(v) {
                const me = this;
                if (me.isUp) {
                    // fileList更新时会触发，这里通过标识符避免重复触发事件
                    me.isUp = false;
                } else {
                    // 通过标识判断是否是通过value来处理显示值
                    let list = [];
                    if (!isEmpty(v)) {
                        list = v.split(',');
                    }
                    // 设置文件列表
                    me.fileList = me.getList(list);
                }
            }
        },
        // 监听允许上传类型生成校验规则
        acceptType: {
            immediate: true,
            handler(v) {
                if (!isEmpty(v)) {
                    // 根据允许上传类型确定校验规则文案
                    const me = this,
                        rules = me.rules;
                    let accept, checkList;
                    // 循环遍历生成校验规则数据
                    v.forEach((name) => {
                        const item = find(rules, { name });
                        if (item) {
                            // 上传可选类型
                            accept = concat(accept, item.suffix);
                            // 可选类型校验规则
                            checkList = concat(checkList, item.rule);
                        }
                    });
                    accept = compact(accept).toString();
                    // 设置可选类型
                    me.accept = accept;
                    // 设置校验规则
                    me.acceptRules = checkList;
                    // 设置提示文案
                    me.acceptMessage = `只能上传${accept
                        .replace(/\./g, '')
                        .replace(/\,/g, '、')}格式文件`;
                }
            }
        },
        // 监听文件列表变化
        fileList(v) {
            // console.log("updateValue");
            const me = this,
                data = map(v, 'url');
            me.images = data;
            // 标识当前正在设置数据
            me.isUp = true;
            // 标识当前正在设置数据
            // 更新数据
            me.$emit('updateValue', data.toString());
        }
    },
    filters: {
        formatUrl(v) {
            if (linkVerify(v)) {
                return v;
            }
            return this.oos + v;
        }
    },
    methods: {
        formatUrl(v) {
            if (linkVerify(v)) {
                return v;
            }
            return this.oos + v;
        },
        /**
         * 上传文件之前进行文件格式校验
         * @param {any} [file] 已选文件
         *
         */
        beforeUpload(file) {
            const me = this,
                is = me.acceptRules.includes(file.type);
            // 文件类型检验
            if (!is) {
                me.$message.error(me.acceptMessage);
                return false;
            }
            // 文件大小校验
            if (file.size > me.maxSize) {
                me.$message.error(
                    `文件大小不能超过${me.sizeFormat(me.maxSize)}`
                );
                return false;
            }
            // 如果需要处理图片（如上传头像中的剪切）
            if (me.transformFile) {
                me.transformFile(file);
            } else {
                me.upFile(file);
            }
            return is;
        },
        /**
         * 拦截组件自带上传功能，使用阿里云上传
         * #todo 只是上传的话直接用组件上传也是可以的，这里因时间关系用库实现，但是这个库比较大，有待改进
         *
         */
        emptyFn() { },
        // 上传文件
        upFile(file) {
            const me = this;
            // #todo 可以根据配置判断是覆盖还是追加
            oosUpload(file, 'face/staff').then((data) => {
                if (me.isSingle) {
                    me.fileList = [me.getFileDta(data)];
                } else {
                    me.fileList.push(me.getFileDta(data));
                }
            });
        },
        /**
         * 将数据转化为内部可识别数据
         * @param {Array<string>} [list] 待转化数据
         *
         */
        getList(list) {
            const me = this,
                fileShowList = [];
            // 遍历值填充数据
            list.forEach((url) => {
                fileShowList.push(me.getFileDta({ url }));
            });
            return fileShowList;
        },
        /**
         * 获取单个文件数据
         *
         * @param {*} [{
         *     {string}  url 文件路径（必须）
         *
         *     {any} [file] 文件对象
         *
         * }={}]
         */
        getFileDta({ url, file } = {}) {
            // 获取文件后缀
            const me = this,
                rules = me.rules,
                suffix = me.getSuffix(url),
                // 查找文件是否在规则中
                data = find(rules, (info) => {
                    return info.suffix.includes(`.${suffix}`);
                }),
                // 获取文件预览图片
                icon = data ? data.name : 'unknown',
                // 获取文件大小
                size = file ? file.size : 0,
                // 获取文件名称
                name = file ? file.name : `${me.fileName}.${suffix}` || url;
            return {
                name: me.getName(name),
                url,
                icon,
                size: me.sizeFormat(size)
            };
        },
        /**
         * 格式化文件大小，将单位从b按规则转化为其他单位
         * @param {number} [value] 待转化数据
         *
         */
        sizeFormat(value) {
            if (!value) {
                return '';
            }
            let unit = '',
                i = 0;
            const k = 1024;
            if (value >= k) {
                // 获取转换下标
                i = Math.floor(Math.log(value) / Math.log(k));
            }
            // 获取转换后单位
            unit = ['b', 'k', 'm', 'g'][i];
            // 根据转换下标获取转换后的值
            value = value / Math.pow(k, i);
            // console.log('第一次转换:', value);
            // 根据配置设置小数精度
            value = floor(value, 1);
            return value + unit;
        },
        /**
         * 根据文件路径获取文件名称
         * @param {string} [url] 文件路径
         *
         */
        getName(url) {
            return url.replace(/(.*\/)*([^.]+)/i, '$2');
        },
        /**
         * 根据文件路径获取文件后缀
         * @param {string} [url] 文件路径
         *
         */
        getSuffix(url) {
            return url.replace(/.+\./, '').toLowerCase();
        },
        /**
         * 删除已上传文件
         * @param {string} [url] 文件路径
         *
         */
        onDelClick({ url }) {
            // 直接移除数据界面不能实时更新，所以用filter
            this.fileList = filter(this.fileList, function (item) {
                return item.url != url;
            });
        },
        // 模板还没有上传到oos中
        onDownTemplateClick() {
            this.$message.warning('暂无模板');
        }
    }
};
</script>
<style scoped lang="scss">
.item-el {
    width: 140px;
    height: 140px;
    border: 1px solid #e8e8e8;
    margin: 0 5px;

    &.text {
        line-height: 1 !important;
    }
}

::v-deep.file-item.upload-item {
    line-height: 0 !important;
}
</style>
